#include "TeamManager.h"
#include "LogEx.h"
#include "Utils.h"
#include "ServerManager.h"
#include "Timer.h"
#include <string>
#include "RoomManager.h"
#include "PlayerBase.h"
#include "Hall.h"
using namespace std;
using namespace SGLib;

SINGLETON_CLASS_INIT(CTeamManager);

void CTeamManager::Init(s32 gameid, s32 count, s32 teamMinCount, s32 teamMaxCount, s32 teamMatchMode)
{
    if( count < 0 || count > E_MaxQue_Count )
    {
        count = 1;
    }
    m_gameid = gameid;
    m_teamMinCount = teamMinCount;
    m_teamMaxCount = teamMaxCount;
    m_teamMatchMode = teamMatchMode;
    
    m_teamQue.resize( count );
    m_timerId = CServerManager::Instance().AddTimer(
        E_Timer_BuildTeam, CTeamManager::_OnTimerBuildTeam, NULL, 0, true );
    LOG_INFO( "[%s][%s][%d] game[%d] count[%d] teamcount[%d-%d] tid[%d] teamMatchMode[%d]",
        __FILE__, __FUNCTION__, __LINE__, 
        gameid, count, teamMinCount, teamMaxCount, m_timerId, m_teamMatchMode );
}

void CTeamManager::Fini()
{
    if( m_timerId != CTimer<1>::E_Invalid_TimerId )
    {
        CServerManager::Instance().DelTimer( m_timerId );
        m_timerId = CTimer<1>::E_Invalid_TimerId;
    }
}

s32 CTeamManager::GetQueCount()
{
    return (s32)m_teamQue.size();
}

s32 CTeamManager::GetUserQueIdx(u64 userid)
{
    s32 idx = 0;
    std::map<u64, _userTeamInfo>::iterator it = m_userTeamInfo.find( userid );
    if( it == m_userTeamInfo.end() )
    {
        _userTeamInfo ut;
        ut._queIdx = idx;
        ut._lastTime = TIME_NOW;
        m_userTeamInfo[ userid ] = ut;
    }
    else
    {
        idx = it->second._queIdx;
    }
    LOG_DEBUG( "[%s][%s][%d] user[%llu] idx[%d]",
        __FILE__, __FUNCTION__, __LINE__, userid, idx );
    return idx;
}

void CTeamManager::SetUserQueIdx(u64 userid, s32 idx)
{
    if( idx < 0 || idx >= (s32)m_teamQue.size() )
    {
        idx = 0;
    }
    std::map<u64, _userTeamInfo>::iterator it = m_userTeamInfo.find( userid );
    if( it == m_userTeamInfo.end() )
    {
        _userTeamInfo ut;
        ut._queIdx = idx;
        ut._lastTime = TIME_NOW;
        m_userTeamInfo[ userid ] = ut;
    }
    else
    {
        it->second._queIdx = idx;
        it->second._lastTime = TIME_NOW;
    }
    LOG_DEBUG( "[%s][%s][%d] user[%llu] idx[%d]",
        __FILE__, __FUNCTION__, __LINE__, userid, idx );
}

void CTeamManager::AddUser(u64 userid)
{
    if( IsWaiting(userid) )
    {
        LOG_WARN( "[%s][%s][%d] user[%llu] aleardy waiting",
            __FILE__, __FUNCTION__, __LINE__, userid );
        return;
    }
    
    s32 idx = GetUserQueIdx( userid );
    m_teamQue[idx]._que.insert( userid );
    LOG_INFO( "[%s][%s][%d] user[%llu] idx[%d] queSize[%d]",
        __FILE__, __FUNCTION__, __LINE__, userid, idx, m_teamQue[idx]._que.size() );
}

void CTeamManager::RemoveUser(u64 userid)
{
    std::vector<_teamQue>::iterator it = m_teamQue.begin();
    for( s32 idx=0; it != m_teamQue.end(); ++it, ++idx )
    {
        std::set<u64>::iterator sit = it->_que.find( userid );
        if( sit != it->_que.end() )
        {
            it->_que.erase( sit );
            LOG_INFO( "[%s][%s][%d] user[%llu] fromidx[%d] queSize[%d]",
                __FILE__, __FUNCTION__, __LINE__, userid, idx, it->_que.size() );
        }
    }
}

void CTeamManager::_OnTimerBuildTeam(void *data, s32 len)
{
    CTeamManager::Instance()._TimerBuildTeam();
}

bool CTeamManager::IsWaiting(u64 userid)
{
    std::vector<_teamQue>::iterator it = m_teamQue.begin();
    for( ; it != m_teamQue.end(); ++it )
    {
        if( it->_que.find(userid) != it->_que.end() )
        {
            return true;
        }
    }
    return false;
}

void CTeamManager::_TimerBuildTeam()
{
    switch( m_teamMatchMode )
    {
    case E_MatchMode_FixedUser:
        _BuildTeam_Common();
        break;
    case E_MatchMode_FillRoom:
        _BuildTeam_FillRoom();
        break;
    default:
        _BuildTeam_Common();
        break;
    };
}

void CTeamManager::_BuildTeam_Common()
{
    std::vector<_teamQue>::iterator it = m_teamQue.begin();
    for( ; it != m_teamQue.end(); ++it )
    {
        _CommonBuild_1( *it );
    }
}

void CTeamManager::_BuildTeam_FillRoom()
{
    std::vector<_teamQue>::iterator it = m_teamQue.begin();
    for( ; it != m_teamQue.end(); ++it )
    {
        _FillRoomBuild_1( *it );
    }
}

void CTeamManager::_CommonBuild_1(_teamQue &tque)
{
    if( (s32)tque._que.size() < m_teamMinCount )
    {
        return;
    }

    while(1)
    {
        if( (s32)tque._que.size() < m_teamMinCount )
        {
            break;
        }

        s32 roomid = CRoomManager::Instance().GetRoom();
        if( roomid == INVALID_VAL )
        {
            LOG_WARN( "[%s][%s][%d] not empty room",
                __FILE__, __FUNCTION__, __LINE__ );
            break;
        }

        // 匹配
        string _str;
        vector<u64> t;
        for( s32 i=0; i<m_teamMinCount; ++i )
        {
            set<u64>::iterator it = tque._que.begin();
            u64 uid = (*it);
            tque._que.erase( it );
            t.push_back( uid );

            char _tmp[32] = {0};
            sprintf( _tmp, "%llu,", uid );
            _str += _tmp;
        }
        LOG_INFO( "[%s][%s][%d] team[%s] roomid[%d]",
            __FILE__, __FUNCTION__, __LINE__, _str.c_str(), roomid );

        // 匹配成功通知
        commonproto::SCMatchPlayerResultNtf ntf;
        ntf.roomid = roomid;
        	   
        // 进房间
	    CRoomBase *room = CHall::Instance().FindRoom( roomid );
        SELF_ASSERT( room, break; );
        vector<u64>::iterator it = t.begin();
        for( int seatno=0; it != t.end(); ++it, ++seatno )
        {
            CPlayerBase *player =  CHall::Instance().FindPlayer( *it );
            SELF_ASSERT( player, return; );
            player->SendMsg( commonproto::SC_MATCH_PLAYER_RESULT_NTF, ntf );
            CHall::Instance().PlayerEnterRoom( *player, *room, seatno, "" );
        }
    }
}

void CTeamManager::_FillRoomBuild_1(_teamQue &tque)
{
    _teamQue tmp;
    while(1)
    {
        if( (s32)tque._que.size() <= 0 )
        {
            break;
        }

        // 先检查是否有halffull房间，没有则新建个, 
        // 注意如果队列里等待人数不够开房的情况下，不用新分配房间
        if( CRoomManager::Instance().GetHalfFullList().size() <= 0 )
        {
            if( (s32)tque._que.size() < CHallConfig::Instance().GetCfg().minPlayerCount )
            {
                break;
            }
            s32 rid = CRoomManager::Instance().GetRoom();
            if( rid == INVALID_VAL )
            {
                LOG_WARN( "[%s][%s][%d] not empty room",
                        __FILE__, __FUNCTION__, __LINE__ );
                break;
            }
            LOG_DEBUG( "[%s][%s][%d] get new room[%d]",
                __FILE__, __FUNCTION__, __LINE__, rid );
        }

        set<u64>::iterator it = tque._que.begin();
        u64 uid = (*it);
        tque._que.erase( it );
        CPlayerBase *player =  CHall::Instance().FindPlayer( uid );
        if( !player ) continue;

        bool ismatch = false;
        std::set<s32>::const_iterator cit = CRoomManager::Instance().GetHalfFullList().begin();
        for( ; cit != CRoomManager::Instance().GetHalfFullList().end(); ++cit )
        {
            s32 roomid = *cit;
            CRoomBase *room = CHall::Instance().FindRoom( roomid );
            SELF_ASSERT( room, continue; );

            s32 seat = room->FindFreeSeat();
            SELF_ASSERT( seat != INVALID_SEAT, continue; );
            s32 ret = room->CanEnter( *player, seat, "" );
            if( ret == errorcode::E_ErrorCode_Success )
            {
                ismatch = true;
                LOG_INFO( "[%s][%s][%d] user[%llu] roomid[%d] seat[%d] room[%d/%d,%d,%d]",
                    __FILE__, __FUNCTION__, __LINE__, uid, roomid, seat,
                    CRoomManager::Instance().GetFreeCount(), CRoomManager::Instance().GetTotalCount(),
                    CRoomManager::Instance().GetHalfFullCount(), CRoomManager::Instance().GetUsingCount() );

                commonproto::SCMatchPlayerResultNtf ntf;
                ntf.roomid = roomid;
                player->SendMsg( commonproto::SC_MATCH_PLAYER_RESULT_NTF, ntf );

                CHall::Instance().PlayerEnterRoom( *player, *room, seat, "" );
                break;
            }
            else
            {
                LOG_DEBUG( "[%s][%s][%d] user[%llu] enter roomid[%d] seat[%d] failed[%d] room[%d/%d,%d,%d]",
                    __FILE__, __FUNCTION__, __LINE__, uid, roomid, seat, ret,
                    CRoomManager::Instance().GetFreeCount(), CRoomManager::Instance().GetTotalCount(),
                    CRoomManager::Instance().GetHalfFullCount(), CRoomManager::Instance().GetUsingCount() );
            }
        }
        if( !ismatch )
        {
            // 该玩家找不到合适的房间，取一个新房间放到列表里, 等下个匹配时刻时会尝试玩家进新房间
            //s32 rid = CRoomManager::Instance().GetRoom();
            tmp._que.insert( uid );
            LOG_WARN( "[%s][%s][%d] user[%llu] not found room. getnewroom[%d] room[%d/%d] half[%d] using[%d]",
                __FILE__, __FUNCTION__, __LINE__,
                uid, /*rid*/0, CRoomManager::Instance().GetFreeCount(), CRoomManager::Instance().GetTotalCount(), 
                CRoomManager::Instance().GetHalfFullCount(), CRoomManager::Instance().GetUsingCount() );
        }
    }

    tque._que.insert( tmp._que.begin(), tmp._que.end() );
}



